#import <Cocoa/Cocoa.h>



#pragma mark Bindings constants
extern NSString* const ALTimelineContentBinding;
extern NSString* const ALTimelineDateKeyPathOption;

#pragma mark Notification constants
extern NSString* const ALTimelineElementsDidChangeNotification;
extern NSString* const ALTimelineInsertedEntriesKey;
extern NSString* const ALTimelineRemovedEntriesKey;
extern NSString* const ALTimelineMovedEntriesKey;


#pragma mark -
#pragma mark Delegate protocol

@class ALTimelineElement;
@class ALTimelineView;

@protocol ALTimelineViewDelegate <NSObject>
@optional

// Data
-(ALTimelineElement *)timeline:(ALTimelineView *)aTimeline elementForRepresentedObject:(id)object;
-(NSDate *)timeline:(ALTimelineView *)aTimeline dateForRepresentedObject:(id)object;  // If using this to provide dates rather than dateKeyPath, then the delegate is responsible for calling rearrangeObjects when the dates change

// Layout
-(NSSize)timeline:(ALTimelineView *)aTimeline preferredSizeForElement:(ALTimelineElement *)anElement;

// Selection
-(BOOL)timeline:(ALTimelineView *)aTimeline shouldSelectElement:(ALTimelineElement *)element;
-(BOOL)timeline:(ALTimelineView *)aTimeline shouldDeselectElement:(ALTimelineElement *)element;

// Editing
-(BOOL)timeline:(ALTimelineView *)aTimeline shouldEditElement:(ALTimelineElement *)element;

// Event-handling
-(BOOL)timeline:(ALTimelineView *)aTimeline doCommandBySelector:(SEL)aSelector;
-(BOOL)timeline:(ALTimelineView *)aTimeline insertText:(id)aString;
-(NSView *)timeline:(ALTimelineView *)aTimeline willForwardHitTestAtPoint:(NSPoint)aPoint toSubview:(NSView *)subview inElement:(ALTimelineElement *)hitElement;  // aPoint is in same coordinates as NSView's 'hitTest:' which is the receiver's (ALTimelineView's) superview

// Autosaving element size
// TODO: TEST REMOVAL OF STRING FROM USER DEFAULTS WHEN REMOVING THE ELEMENT
-(NSString *)timeline:(ALTimelineView *)aTimeline uniqueStringForRepresentedObject:(id)representedObject;

@end


#pragma mark -
#pragma mark Drag & Drop delegate protocol

@protocol ALTimelineViewDragDropDelegate <NSObject>

@optional
// Dragging source methods
-(NSImage *)timeline:(ALTimelineView *)aTimeline dragImageForElements:(NSArray *)dragElements;
-(BOOL)timeline:(ALTimelineView *)aTimeline writeElements:(NSArray *)elements toPasteboard:(NSPasteboard *)pasteboard;
-(NSDragOperation)timeline:(ALTimelineView *)aTimeline draggingSourceOperationForLocal:(BOOL)isLocal;

// Dragging destination methods
-(NSDragOperation)timeline:(ALTimelineView *)aTimeline validateDrop:(id <NSDraggingInfo>)dragInfo proposedElement:(ALTimelineElement *)element proposedIndex:(NSUInteger)elementIndex;
-(BOOL)timeline:(ALTimelineView *)aTimeline acceptDrop:(id <NSDraggingInfo>)dragInfo element:(ALTimelineElement *)element index:(NSUInteger)index;

@end


@class ALTimelineCanvas;
@class ALTimelineScale;

#pragma mark -
@interface ALTimelineView : NSView <NSAnimationDelegate> {
}

#pragma mark -
#pragma mark Components
@property (nonatomic, retain) ALTimelineCanvas *canvas;
@property (nonatomic, retain) ALTimelineScale *scale;


#pragma mark -
#pragma mark Delegate objects
@property (nonatomic, assign) IBOutlet id<ALTimelineViewDelegate> delegate;
@property (nonatomic, assign) IBOutlet id<ALTimelineViewDragDropDelegate> dragDropDelegate;


#pragma mark -
#pragma mark Data
@property (nonatomic, retain) IBOutlet ALTimelineElement *elementPrototype;
@property (nonatomic, retain, readonly) NSArray *timelineElements;
@property (nonatomic, copy) NSString *dateKeyPath;
@property (nonatomic, assign, readonly) NSUInteger totalDays;  // Total number of days from first to last element, observable
-(NSArray *)arrangeObjects:(NSArray *)objects;
-(void)rearrangeObjects;


#pragma mark -
#pragma mark Finding and sorting elements
//@property (nonatomic, retain) NSArray *elementSortDescriptors;

-(ALTimelineElement *)elementWithRepresentedObject:(id)object returnIndex:(NSUInteger *)elementIndex;
-(ALTimelineElement *)elementWithView:(NSView *)aView;


#pragma mark -
#pragma mark Geometry
-(void)scrollElementToVisible:(ALTimelineElement *)element;
-(NSRect)canvasRectForBounds:(NSRect)bounds;
-(NSRect)scaleRectForBounds:(NSRect)bounds;


#pragma mark -
#pragma mark Layout

-(void)tile;


#pragma mark -
#pragma mark Selection
@property (nonatomic, retain, readonly) NSArray *selectedElements;

-(NSArray *)selectedObjects; // Observable

-(BOOL)selectElement:(ALTimelineElement *)element extendSelection:(BOOL)shouldExtend;
-(BOOL)selectElements:(NSArray *)elements extendSelection:(BOOL)shouldExtend;
-(BOOL)selectNextElementAndExtendSelection:(BOOL)shouldExtend;
-(BOOL)selectPreviousElementAndExtendSelection:(BOOL)shouldExtend;
-(BOOL)selectAllElements;
-(BOOL)deselectElement:(ALTimelineElement *)anElement;
-(BOOL)deselectElements:(NSArray *)elements;
-(BOOL)deselectAllElements;


#pragma mark -
#pragma mark Editing
@property (nonatomic, retain, readonly) ALTimelineElement *editingElement;

-(void)stopEditing;
-(BOOL)editElement:(ALTimelineElement *)element atPoint:(NSPoint)clickPoint;  // Point is in the given element view's coordinates


#pragma mark -
#pragma mark Drag & drop


@end
